package com.tetris

import android.content.Context
import android.media.MediaPlayer
import android.os.Handler
import android.os.Handler.Callback
import android.os.Looper
import android.os.Message

import androidx.compose.foundation.Canvas
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableIntState
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.DrawScope

import java.util.Random
import java.util.Timer
import java.util.TimerTask

import kotlin.math.abs

// 游戏
class Game: Callback {
    // 状态
    enum class Status {
        CREATING,   // 正在创建游戏物体
        END,        // 已结束
        LOST,       // 游戏失败
        PAUSED,     // 暂停中
        PLAYING,    // 游戏中
        STARTING,   // 正在开始
        WON         // 游戏胜利
    }

    // 定时器任务类
    private class GameTimerTask(callback: Callback): TimerTask() {
        private val mCallback = Handler(Looper.getMainLooper(), callback)   // 回调

        /**
         * 定时器事件的响应方法。
         */
        override fun run() {
            mCallback.sendEmptyMessage(Const.UM_TIMER)
        }
    }

    companion object {
        lateinit var sExistentBlocks: SnapshotStateList<SnapshotStateList<ColorGrid>>   // 累积的方块
    }

    private var mCurBlock: Block? = null                        // 当前方块
    private lateinit var mDifficulty: MutableIntState           // 难度
    private lateinit var mEnableMusic: MutableState<Boolean>    // 音乐开关
    private val mMusicPlayer: MediaPlayer                       // 音乐播放者
    private var mNextBlock: Block? = null                       // 下一个方块
    private val mRandom: Random                                 // 随机数生成器
    private lateinit var mScore: MutableIntState                // 得分
    private lateinit var mStatus: MutableState<Status>          // 状态
    private val mTimer: Timer                                   // 定时器
    private var mTimerTask: TimerTask? = null                   // 定时器任务
    private var mTop: Int                                       // 有方块的最高行

    /**
     * 构造方法。
     * @param context   设备环境
     */
    constructor(context: Context) {
        mMusicPlayer = MediaPlayer.create(context, R.raw.music)
        mMusicPlayer.isLooping = true
        mRandom = Random()
        mTimer = Timer()
        mTop = Const.GAME_BOARD_GRID_COUNT_V + 1
    }

    /**
     * 检查是否存在满行。
     */
    private fun checkRow() {
        // 更新"有方块的最高行"
        val top = mCurBlock!!.top
        if (top < mTop) {
            mTop = top
        }

        var released = 0    // 消除的行数
        val bottom = mCurBlock!!.bottom

        // 从有方块的最上面一行，到当前方块所占的最下一行，逐行检查
        for (i in mTop..bottom) {
            for (j in 0 ..< Const.GAME_BOARD_GRID_COUNT_H) {
                // 如果该行有空的，就跳过该行
                if (!sExistentBlocks[i][j].mUsed) {
                    break
                }
                // 如果该行满了，消除该行
                if (j == Const.GAME_BOARD_GRID_COUNT_H - 1) {
                    this.releaseRow(i)
                    released++
                }
            }
        }

        if (released > 0) {
            // 计算得分
            mScore.intValue += released * released * 100

            // 计算难度
            if (mScore.intValue / Const.DIFF_BASE + 1 > mDifficulty.intValue && mDifficulty.intValue < Const.DIFF_MAX) {
                // 增加难度
                mDifficulty.intValue++
                mTimerTask!!.cancel()
                mTimerTask = GameTimerTask(this)
                val elapse = Const.TIMER_INIT - Const.TIMER_GROW * (mDifficulty.intValue - 1)
                mTimer.schedule(mTimerTask, elapse, elapse)
            }
        }
    }

    /**
     * 随机创建一种方块。
     * @return 方块
     */
    private fun createRandBlock(): Block {
        val random = abs((mRandom.nextInt() % 7).toDouble()).toInt() + 1

        when (random) {
            1 -> return Block1()
            2 -> return Block2()
            3 -> return Block3()
            4 -> return Block4()
            5 -> return Block5()
            6 -> return Block6()
            7 -> return Block7()
        }

        return Block1()
    }

    /**
     * 获取难度。
     */
    val difficulty: Int
        get() = mDifficulty.intValue

    /**
     * 画累积的方块。
     * @param drawer    绘图者
     */
    private fun drawExistentBlock(drawer: DrawScope) {
        for (i in 0 ..< Const.GAME_BOARD_GRID_COUNT_V) {
            for (j in 0 ..< Const.GAME_BOARD_GRID_COUNT_H) {
                if (sExistentBlocks[i][j].mUsed) {
                    drawer.drawRect(sExistentBlocks[i][j].mColor,
                        Offset(Const.GRID_SIZE * j, Const.GRID_SIZE * i), Size(Const.GRID_SIZE, Const.GRID_SIZE))
                    Block.drawEdge(drawer, Const.GRID_SIZE * j, Const.GRID_SIZE * i)
                }
            }
        }
    }

    /**
     * 音乐开关。
     */
    val enableMusic: Boolean
        get() = mEnableMusic.value

    /**
     * 创建游戏区域。
     * @param modifier  修饰符
     */
    @Composable
    fun GameBoard(modifier: Modifier) {
        // 初始化成员
        mDifficulty = remember {
            mutableIntStateOf(1)
        }
        mEnableMusic = remember {
            mutableStateOf(false)
        }
        mScore = remember {
            mutableIntStateOf(0)
        }
        mStatus = remember {
            mutableStateOf(Status.END)
        }
        sExistentBlocks = remember {
            mutableStateListOf<SnapshotStateList<ColorGrid>>()
        }
        for (i in 0 ..< Const.GAME_BOARD_GRID_COUNT_V) {
            val subList = remember {
                mutableStateListOf<ColorGrid>()
            }
            repeat(Const.GAME_BOARD_GRID_COUNT_H) {
                subList.add(ColorGrid())
            }
            sExistentBlocks.add(i, subList)
        }
        if (mStatus.value == Status.STARTING || mStatus.value == Status.CREATING) {
            this.nextBlock()
            mCurBlock!!.Init()
            mNextBlock!!.Init()
            mStatus.value = Status.PLAYING
        }

        // 创建游戏区域
        Canvas(modifier) {
            mCurBlock?.draw(this)
            this@Game.drawExistentBlock(this)
        }
    }

    /**
     * 游戏结束。
     * @param status    游戏状态
     */
    private fun gameOver(status: Status) {
        // 设置游戏状态
        mStatus.value = status

        // 停止定时器
        mTimerTask!!.cancel()

        // 停止播放音乐
        if (mEnableMusic.value) {
            try {
                mMusicPlayer.stop()
                mMusicPlayer.prepare()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    /**
     * 自定义事件的响应方法。
     * @param message   事件
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    override fun handleMessage(message: Message): Boolean {
        this.moveBlockDown()
        return true
    }

    /**
     * 判断是否失败。
     * @return 失败则返回 true，否则返回 false
     */
    private val isLost: Boolean
        get() = (mTop == 0 && sExistentBlocks[0][4].mUsed)

    /**
     * 判断是否胜利。
     * @return 胜利则返回 true，否则返回 false
     */
    private val isWon: Boolean
        get() = mScore.intValue >= Const.WIN_NUMBER

    /**
     * 方块下落。
     */
    val moveBlockDown = fun() {
        if (this.status != Status.PLAYING) {
            return
        }

        val canMoveDown = mCurBlock!!.moveDown()
        if (!canMoveDown) {
            // 检查是否存在满行
            this.checkRow()

            // 判断是否胜利
            if (this.isWon) {
                this.gameOver(Status.WON)
                return
            }

            // 判断是否失败
            if (this.isLost) {
                this.gameOver(Status.LOST)
                return
            }

            // 产生新的方块
            mStatus.value = Status.CREATING
        }
    }

    /**
     * 方块左移。
     */
    val moveBlockLeft = fun() {
        if (this.status == Status.PLAYING) {
            mCurBlock!!.moveLeft()
        }
    }

    /**
     * 方块右移。
     */
    val moveBlockRight = fun() {
        if (this.status == Status.PLAYING) {
            mCurBlock!!.moveRight()
        }
    }

    /**
     * 产生新的方块。
     */
    private fun nextBlock() {
        // 创建当前方块
        mCurBlock = if (mCurBlock != null) mNextBlock else this.createRandBlock()

        // 创建下一个方块
        mNextBlock = this.createRandBlock()
    }

    /**
     * 游戏暂停。
     */
    val pause = fun() {
        if (this.status == Status.PLAYING) {
            // 停止定时器
            mTimerTask!!.cancel()

            // 停止播放音乐
            if (mEnableMusic.value) {
                mMusicPlayer.pause()
            }

            // 将状态设置为已结束
            mStatus.value = Status.PAUSED
        } else if (this.status == Status.PAUSED) {
            // 开启定时器
            mTimerTask = GameTimerTask(this)
            val elapse = Const.TIMER_INIT - Const.TIMER_GROW * (mDifficulty.intValue - 1)
            mTimer.schedule(mTimerTask, elapse, elapse)

            // 播放音乐
            if (mEnableMusic.value) {
                mMusicPlayer.start()
            }

            // 将状态设置为游戏中
            mStatus.value = Status.PLAYING
        }
    }

    /**
     * 播放音乐。
     */
    val playMusic = fun() {
        mEnableMusic.value = !mEnableMusic.value

        if (mEnableMusic.value) {
            if (this.status == Status.PLAYING) {
                mMusicPlayer.start()
            }
        } else {
            mMusicPlayer.pause()
        }
    }

    /**
     * 创建预览区域。
     * @param modifier  修饰符
     * @param width     宽度
     * @param height    高度
     */
    @Composable
    fun Preview(modifier: Modifier, width: Float, height: Float) {
        Canvas(modifier) {
            mNextBlock?.enterPreview(width, height, this)
        }
    }

    /**
     * 获取得分。
     */
    val score: Int
        get() = mScore.intValue

    /**
     * 消行。
     * @param row   行号
     */
    private fun releaseRow(row: Int) {
        // 最上行
        if (row == 0) {
            for (j in 0 ..< Const.GAME_BOARD_GRID_COUNT_H) {
                sExistentBlocks[row][j].mUsed = false
            }
            mTop++
            return
        }

        // 非最上行
        var used = false
        var color = Color.Unspecified
        for (i in row downTo mTop + 1) {
            for (j in 0 ..< Const.GAME_BOARD_GRID_COUNT_H) {
                used = sExistentBlocks[i - 1][j].mUsed
                sExistentBlocks[i][j].mUsed = used
                color = sExistentBlocks[i - 1][j].mColor
                sExistentBlocks[i][j].mColor = color
            }
        }

        for (j in 0..<Const.GAME_BOARD_GRID_COUNT_H) {
            sExistentBlocks[mTop][j].mUsed = false
        }

        mTop++
    }

    /**
     * 游戏开始。
     */
    val start = fun() {
        // 将状态设置为开始中
        mStatus.value = Status.STARTING

        // 创建方块
        for (i in 0 ..< Const.GAME_BOARD_GRID_COUNT_V) {
            for (j in 0 ..< Const.GAME_BOARD_GRID_COUNT_H) {
                sExistentBlocks[i][j] = ColorGrid()
            }
        }

        // 重置难度
        mDifficulty.intValue = 1

        // 重置分数
        mScore.intValue = 0

        // 开启定时器
        if (mStatus.value == Status.CREATING || mStatus.value == Status.PLAYING || mStatus.value == Status.STARTING) {
            mTimerTask?.cancel()
        }
        mTimerTask = GameTimerTask(this)
        mTimer.schedule(mTimerTask, Const.TIMER_INIT, Const.TIMER_INIT)

        // 播放音乐
        if (enableMusic) {
            mMusicPlayer.start()
        }
    }

    /**
     * 获取游戏状态。
     */
    val status: Status
        get() = mStatus.value

    /**
     * 方块变形。
     */
    val transformBlock = fun() {
        if (this.status == Status.PLAYING) {
            mCurBlock!!.transform()
        }
    }
}
